<?php

// no direct access
defined('_JEXEC') or die('Restricted access');

/**
 * This file is part of the PHP_Word_Cloud project.
 * http://github.com/sixty-nine/PHP_Word_Cloud
 *
 * @author Daniel Barsotti / dan [at] dreamcraft [dot] ch
 * @license http://creativecommons.org/licenses/by-nc-sa/3.0/
 *          Creative Commons Attribution-NonCommercial-ShareAlike 3.0
 */

/**
 * Table of words and frequencies along with some additionnal properties.
 */
class FrequencyTable
{

    const WORDS_HORIZONTAL = 0;
    const WORDS_MAINLY_HORIZONTAL = 1;
    const WORDS_MIXED = 6;
    const WORDS_MAINLY_VERTICAL = 9;
    const WORDS_VERTICAL = 10;

    private $table = array();

    //TODO reuse stopwords not use since tags are already filtered out in cedTag
    private $rejected_words = array(
        'and', 'our', 'your', 'their', 'his', 'her', 'the', 'you', 'them', 'yours',
        'with', 'such', 'even');
    private $font;
    private $vertical_freq = FrequencyTable::WORDS_MAINLY_HORIZONTAL;
    private $total_occurences = 0;
    private $min_font_size = 16;
    private $max_font_size = 25;

    private $max_count = 1;
    private $min_count = 1;
    private $padding_size = 1.05;
    private $padding_angle = 0;
    private $words_limit;

    /**
     * Construct a new FrequencyTable from a word list and a font
     * @param string $text The text containing the words
     * @param string $font The TTF font file
     * @param integer $vertical_freq Frequency of vertical words (0 - 10, 0 = All horizontal, 10 = All vertical)
     */
    public function __construct($minFontSize, $maxFontSize,
                                $font, $text = '',
                                $vertical_freq = FrequencyTable::WORDS_MAINLY_HORIZONTAL,
                                $words_limit = null)
    {
        $this->words_limit = $words_limit;
        $this->font = $font;
        $this->vertical_freq = $vertical_freq;
        $this->min_font_size = $minFontSize;
        $this->max_font_size = $maxFontSize;
    }

    public function processText($text)
    {
        $words = preg_split("/[\n\r\t ]+/", $text);
        $this->create_frequency_table($words);
    }

    public function buildCloud()
    {
        $this->process_frequency_table();
    }

    public function setMinFontSize($val)
    {

        $this->min_font_size = $val;
    }

    public function setMaxFontSize($val)
    {

        $this->max_font_size = $val;
    }

    public function add_word($word, $nbr_occurence = 1, $title = null, $link = '')
    {
        $this->insert_word($word, $nbr_occurence, $title, $link);
    }

    /**
     * Return the current frequency table
     */
    public function get_table()
    {
        $this->process_frequency_table();
        return $this->table;
    }

    private function insert_word($word, $count = 1, $title = null, $link = '', $reject = false, $cleanup = false)
    {
        // Reject unwanted words
        $word = strtolower($word);
        if (($reject) && ((strlen($word) < 3) || (in_array($word, $this->rejected_words)))) {
            return;
        } else {

            if ($cleanup) {
                $word = $this->cleanup_word($word);
            }


            if (array_key_exists($word, $this->table)) {
                $this->table[$word]->count += $count;
            } else {
                $this->table[$word] = new StdClass();
                $this->table[$word]->count = $count;
                $this->table[$word]->word = $word;
                $this->table[$word]->title = $title;
                $this->table[$word]->link = $link;

            }
            $this->total_occurences += $count;
            if ($this->table[$word]->count > $this->max_count) {
                $this->max_count = $this->table[$word]->count;
            }
        }
    }

    /**
     * Creates the frequency table from a text.
     * @param string $words The text containing the words
     */
    private function create_frequency_table($words)
    {
        foreach ($words as $key => $word) {
            $this->insert_word($word);
        }
    }

    /**
     * Calculate word frequencies and set additionnal properties of the frequency table
     * @param integer $vertical_freq Frequency of vertical words (0 - 10, 0 = All horizontal, 10 = All vertical)
     */
    private function process_frequency_table()
    {
        arsort($this->table);
        $count = count($this->table);
        $diffcount = ($this->max_count - $this->min_count) != 0 ? ($this->max_count - $this->min_count) : 1;
        $diffsize = ($this->max_font_size - $this->min_font_size) != 0 ? ($this->max_font_size - $this->min_font_size) : 1;
        $slope = $diffsize / $diffcount;
        $yintercept = $this->max_font_size - ($slope * $this->max_count);

        //cut the table so we have only $this->words_limit
        $this->table = array_slice($this->table, 0, $this->words_limit);

        foreach ($this->table as $key => $val) {
            $font_size = (integer)($slope * $this->table[$key]->count + $yintercept);

            // Set min/max val for font size
            if ($font_size < $this->min_font_size) {
                $font_size = $this->min_font_size;
            } elseif ($font_size > $this->max_font_size) {
                $font_size = $this->max_font_size;
            }
            $this->table[$key]->size = $font_size;

            $this->table[$key]->angle = 0;
            if (rand(1, 10) <= $this->vertical_freq) $this->table[$key]->angle = 90;
            $this->table[$key]->box = imagettfbbox($this->table[$key]->size * $this->padding_size, $this->table[$key]->angle - $this->padding_angle, $this->font, $key);
        }
    }

    /**
     * Remove unwanted characters from a word
     * @param string $word The word to clenup
     * @return string The cleaned up word
     */
    private function cleanup_word($word)
    {

        $tmp = $word;

        // Remove unwanted characters
        $punctuation = array('?', '!', '\'', '"');
        foreach ($punctuation as $p) {
            $tmp = str_replace($p, '', $tmp);
        }

        // Remove trailing punctuation
        $punctuation[] = '.';
        $punctuation[] = ',';
        $punctuation[] = ':';
        foreach ($punctuation as $p) {
            if (substr($tmp, -1) == $p) {
                $tmp = substr($tmp, 0, -1);
            }
        }
        return $tmp;
    }

}
